Assignment 1
Problem 1#
An alternating sequence is a sequence of integers such that its elements satisfy one of the following two properties:
The algorithm below is a simple iterative algorithm that returns true iff a sequence is alternating.
fun isAlternating(A[1..n]) if n < 2 return true if A[1] == A[2] return false
prev = A[1] < A[2] for i = 3 to n: if(A[i-1] == A[i]) return false
current = A[i-1] < A[i] if(prev == current) return false prev = current
postcond A[1..n] is an alternating sequence return trueQuestions#
- (8 points) Prove the full correctness of isAlternating. Remember to clearly state your loop invariants and any necessary preconditions.
Answers#
- Precondition: has a length greater than 1 and the first two elements are different.
LI: is alternating.- Initialization: The precondition asserts that the array contains at least two elements and those elements are not equal. If the two elements are different, is alternating. Thus, LI(1) is true.
- Maintenance: For all i > 2, assume L(i-1) holds. In the i-1th iteration, is alternating. There are 3 cases:
- is equal to . These numbers do not alternate.
falseis returned and the loop is broken. - ==
prev, then is ascending or descending, and the array does not alternate.falseis returned and the loop is broken. - !=
prev, then is alternating. L(i) holds.
- is equal to . These numbers do not alternate.
- Termination: The loop can break in two ways:
- The array is not alternating. The loop breaks after returning
false. The postcondition holds. - The loop iterates to
n. In this case, the entire array was exhausted. Per maintenance of the loop invariant, the array is alternating and no value was returned. The loop exits andtrueis returned. Thus, the postcondition holds.
- The array is not alternating. The loop breaks after returning
Problem 2#
Suppose you are given two arrays and of integers. You are required to find a pair of elements such that their absolute difference is the smallest over all such pairs.
Questions#
- (3 points) Describe a brute force algorithm that solves the problem and informally justify its running time.
- (8 points) Assume A and B are sorted in non-decreasing order. Design a algorithm for the problem. Provide a clear and concise pseudocode. Hint: the idea is quite similar to that of the Merge algorithm from Merge Sort.
- (8 points) Prove the correctness of your algorithm.
Answers#
A brute force method would be to compare each element in against every element in and find their absolute difference. This would have a running time of as it would require 2 nested loops running from each with an if statement checking if is less than the existing minimum difference.
fun absDiff(A[1..n], B[1..n]) diff = ꝏ x = 1 y = 1 while x < n && y < n if abs(A[x] - B[y]) < diff diff = abs(A[x] - B[y]) i = A[x] j = B[y] if (A[x] < B[y]) x++ else y++ return {i, j}Precondition: and are both sorted arrays in non-descending order.
LI:diffcontains the smallest absolute difference between and .Initialization: Before the first iteration,
diffis equal to infinity. This is done so that no two numbers can have a greater absolute difference as the difference between and is undefined. Thus, LI(1) is true.Maintenance: For all
xandy>1, assume L((x or y)-1) holds. Therefore, L((x or y)-1):absDiff(A[1..x], B[1..y])contains the smallest difference in that set. There are 2 cases:The absolute difference between and is less than the current minimum difference. In this case,
diffis updated to reflect the new minimum difference.The absolute difference between and is not less than the current minimum difference. In this case,
diffis left unchanged.
- After either of the above cases, either x or y are incremented depending on the values of and and the loop continues.
Termination: The loop can terminate in one of two ways:
After iterating through the entirety of ,
xis incremented and is now equal ton. The loop is broken.iandjare returned.After iterating through the entirety of ,
yis incremented and is now equal ton. The loop is broken.iandjare returned.
Problem 3#
The algorithm below checks whether is a substring of .
fun isSubstring(S1[1..n], S2[1..m]) if n > m return false
for i = 1 to m: isSub = true for j = 1 to n: if S1[j] != S2[i+j-1]: isSub = false break
if(isSub) return true return falseQuestions#
- (2 points) What is the best case and worst case in terms of running time?
- (5 points) Compute the exact running time of isSubstring.
- (1 points) Give a suggestion on how the running time could be reduced.
Answers#
The best case is , the average case is , and the worst case is .
Line # Cost Occurrences 2 3 5 6 7 8 9 10 12 13 14 Thus, the total cost is . Simplified, this shows us that the cost is .
Adding a good hash function will reduce the average running time.
Problem 4#
Not-A-Dr. Oreo is teaching a course on the design and analysis of algorithms. To determine the best day of the week for his students to write the quiz, he ran a poll asking each of his student to pick a day (in his world a week has an infinite number of days). Oreo collected all the answers of his students in an array where is the day chosen by student . He needs your help in determining the winning day. The winning day is the day picked by more than students. You may assume that there will always be a winning day.
Questions#
- (3 points) Describe a brute force algorithm that solves the problem in .
- (8 points) Give a more efficient algorithm that solves the problem using a divide and conquer strategy. Remember to provide a clear and concise pseudocode.
- (4 points) Use a recurrence relation to prove an upper bound for your algorithm.
- (2 points) Bonus: Assuming Oreo's weeks have 7 days (i.e., ), give a linear time algorithm for the problem.
Answers#
A brute force algorithm that solves the problem in would be the following: for each student in the class (), check if any subsequent students () share the same chosen day. If the number of matches is greater than , return that day. Otherwise, move on to the next student (). Repeat until a date is chosen
Assume all integers are 'truthy'
fun quizDate(A[1..n]) if A.length == 1 return A[0] else if A.length == 2 if A[0] == A[1] return A[0] else return false mid = A.length / 2 B = quizDate(A[1..mid]) C = quizDate(A[mid+1..n]) if !B && C return C else if (!C && B) || B == C return B return false
- The above algorithm shares a lot of similarities with merge sort. Namely, in the divide step. The array is continuously split in two, meaning there are divisions. At the base, there are nodes, meaning it is
- The returned number corresponds to the day of the week starting with Sunday as 1, and ending with Saturday as 7.
fun quizDate7(A[1..n]) B = [0, 0, 0, 0, 0, 0, 0] for i = 1 to n B[A[i]]++ for j = 1 to 7 if B[j] > n/2 return j